/**
 * Copyright &copy; 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package org.kunteng.yunac.modules.sys.service;

import java.text.SimpleDateFormat;
import java.util.*;

import org.kunteng.yunac.modules.sys.dao.SystemDao;
import net.sf.json.JSONObject;
import org.apache.shiro.session.Session;
import org.kunteng.yunac.common.config.Global;
import org.kunteng.yunac.common.utils.CacheUtils;
import org.kunteng.yunac.modules.sys.entity.Menu;
import org.kunteng.yunac.modules.sys.security.SystemAuthorizingRealm;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import org.kunteng.yunac.common.persistence.Page;
import org.kunteng.yunac.common.security.Digests;
import org.kunteng.yunac.common.security.shiro.session.SessionDAO;
import org.kunteng.yunac.common.service.BaseService;
import org.kunteng.yunac.common.utils.Encodes;
import org.kunteng.yunac.common.utils.StringUtils;
import org.kunteng.yunac.modules.sys.dao.MenuDao;
import org.kunteng.yunac.modules.sys.dao.UserDao;
import org.kunteng.yunac.modules.sys.entity.User;
import org.kunteng.yunac.modules.sys.utils.LogUtils;
import org.kunteng.yunac.modules.sys.utils.UserUtils;

import net.sf.json.JSONArray;

/**
 * 系统管理，安全相关实体的管理类,包括用户、角色、菜单.
 *
 * @author ThinkGem
 * @version 2013-12-05
 */
@Service
@Transactional(readOnly = true)
public class SystemService extends BaseService implements InitializingBean {

    public static final String HASH_ALGORITHM = "SHA-1";
    public static final int HASH_INTERATIONS = 1024;
    public static final int SALT_SIZE = 8;

    @Autowired
    private UserDao userDao;
    @Autowired
    private MenuDao menuDao;
    @Autowired
    private SystemDao systemDao;

    @Autowired
    private SessionDAO sessionDao;
    @Autowired
    private SystemAuthorizingRealm systemRealm;

    public SessionDAO getSessionDao() {
        return sessionDao;
    }


    //-- User Service --//

    /**
     * 获取用户
     *
     * @param id
     * @return
     */
    public User getUser(String id) {
        return UserUtils.get(id);
    }

    /**
     * 根据登录名获取用户
     *
     * @param loginName
     * @return
     */
    public User getUserByLoginName(String loginName) {
        return UserUtils.getByLoginName(loginName);
    }

    public Page<User> findUser(Page<User> page, User user) {
        // 生成数据权限过滤条件（dsf为dataScopeFilter的简写，在xml中使用 ${sqlMap.dsf}调用权限SQL）
        user.getSqlMap().put("dsf", dataScopeFilter(user.getCurrentUser(), "o", "a"));
        // 设置分页参数
        user.setPage(page);
        // 执行分页查询
        page.setList(userDao.findList(user));
        return page;
    }

    /**
     * 无分页查询人员列表
     *
     * @param user
     * @return
     */
    public List<User> findUser(User user) {
        // 生成数据权限过滤条件（dsf为dataScopeFilter的简写，在xml中使用 ${sqlMap.dsf}调用权限SQL）
        user.getSqlMap().put("dsf", dataScopeFilter(user.getCurrentUser(), "o", "a"));
        List<User> list = userDao.findList(user);
        return list;
    }

    @Transactional(readOnly = false)
    public void saveUser(User user) {
        if (StringUtils.isBlank(user.getId())) {
            user.preInsert();
            userDao.insert(user);
        } else {
            // 清除原用户机构用户缓存
            User oldUser = userDao.get(user.getId());
//			if (oldUser.getOffice() != null && oldUser.getOffice().getId() != null){
//				CacheUtils.remove(UserUtils.USER_CACHE, UserUtils.USER_CACHE_LIST_BY_OFFICE_ID_ + oldUser.getOffice().getId());
//			}
            // 更新用户数据
            user.preUpdate();
            userDao.update(user);
        }
        if (StringUtils.isNotBlank(user.getId())) {
            // 更新用户与角色关联
            userDao.deleteUserRole(user);
//			if (user.getRoleList() != null && user.getRoleList().size() > 0){
//				userDao.insertUserRole(user);
//			}else{
//				throw new ServiceException(user.getLoginName() + "没有设置角色！");
//			}
            // 清除用户缓存
            UserUtils.clearCache(user);
//			// 清除权限缓存
//			systemRealm.clearAllCachedAuthorizationInfo();
        }
    }

    @Transactional(readOnly = false)
    public void updateUserInfo(User user) {
        user.preUpdate();
        if (user.getAvatar() != null) {
            updateCAvatar(user);
        }
        if (user.getLogo() != null) {
            updateCLogo(user);
        }
        userDao.updateUserInfo(user);
        // 清除用户缓存
        UserUtils.clearCache(user);
//		// 清除权限缓存
//		systemRealm.clearAllCachedAuthorizationInfo();
    }

    private void updateCAvatar(User user) {
        if (userDao.findCAvatar(user) != null) {
            userDao.updateCAvatar(user);
        } else {
            userDao.insertCAvatar(user);
        }
    }

    private void updateCLogo(User user) {
        if (userDao.findCLogo(user) != null) {
            userDao.updateCLogo(user);
        } else {
            userDao.insertCLogo(user);
        }
    }

    @Transactional(readOnly = false)
    public void deleteUser(User user) {
        userDao.delete(user);
        // 清除用户缓存
        UserUtils.clearCache(user);
//		// 清除权限缓存
//		systemRealm.clearAllCachedAuthorizationInfo();
    }

    @Transactional(readOnly = false)
    public void updatePasswordById(String id, String loginName, String newPassword) {
        User user = new User(id);
        user.setPasswd(entryptPassword(newPassword));
        userDao.updatePasswordById(user);
        // 清除用户缓存
        user.setAccount(loginName);
        UserUtils.clearCache(user);
//		// 清除权限缓存
        systemRealm.clearAllCachedAuthorizationInfo();
    }

    @Transactional(readOnly = false)
    public void updateUserLoginInfo(User user) {
        userDao.updateLoginInfo(user);
    }

    /**
     * 生成安全的密码，生成随机的16位salt并经过1024次 sha-1 hash
     */
    public static String entryptPassword(String plainPassword) {
        byte[] salt = Digests.generateSalt(SALT_SIZE);
        byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, HASH_INTERATIONS);
        return Encodes.encodeHex(salt) + Encodes.encodeHex(hashPassword);
    }

    /**
     * 验证密码
     *
     * @param plainPassword 明文密码
     * @param password      密文密码
     * @return 验证成功返回true
     */
    public static boolean validatePassword(String plainPassword, String password) {
        byte[] salt = Encodes.decodeHex(password.substring(0, 16));
        byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, HASH_INTERATIONS);
        return password.equals(Encodes.encodeHex(salt) + Encodes.encodeHex(hashPassword));
    }

    /**
     * 获得活动会话
     *
     * @return
     */
    public Collection<Session> getActiveSessions() {
        return sessionDao.getActiveSessions(false);
    }

    //-- Menu Service --//

    public Menu getMenu(String id) {
        return menuDao.get(id);
    }

    public List<Menu> findAllMenu() {
        return UserUtils.getMenuList();
    }

    @Transactional(readOnly = false)
    public void saveMenu(Menu menu) {

        // 获取父节点实体
        menu.setParent(this.getMenu(menu.getParent().getId()));

        // 获取修改前的parentIds，用于更新子节点的parentIds
        String oldParentIds = menu.getParentIds();

        // 设置新的父节点串
        menu.setParentIds(menu.getParent().getParentIds() + menu.getParent().getId() + ",");

        // 保存或更新实体
        if (StringUtils.isBlank(menu.getId())) {
            menu.preInsert();
            menuDao.insert(menu);
        } else {
            menu.preUpdate();
            menuDao.update(menu);
        }

        // 更新子节点 parentIds
        Menu m = new Menu();
        m.setParentIds("%," + menu.getId() + ",%");
        List<Menu> list = menuDao.findByParentIdsLike(m);
        for (Menu e : list) {
            e.setParentIds(e.getParentIds().replace(oldParentIds, menu.getParentIds()));
            menuDao.updateParentIds(e);
        }
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
//		// 清除权限缓存
//		systemRealm.clearAllCachedAuthorizationInfo();
        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    @Transactional(readOnly = false)
    public void updateMenuSort(Menu menu) {
        menuDao.updateSort(menu);
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
//		// 清除权限缓存
//		systemRealm.clearAllCachedAuthorizationInfo();
        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    @Transactional(readOnly = false)
    public void deleteMenu(Menu menu) {
        menuDao.delete(menu);
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
//		// 清除权限缓存
//		systemRealm.clearAllCachedAuthorizationInfo();
        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    /**
     * 获取Key加载信息
     */
    public static boolean printKeyLoadMessage() {
        StringBuilder sb = new StringBuilder();
        sb.append("\r\n======================================================================\r\n");
        sb.append("\r\n    欢迎使用 " + Global.getConfig("productName") + "  - Powered By http://www.kunteng.org/\r\n");
        sb.append("\r\n======================================================================\r\n");
        System.out.println(sb.toString());
        return true;
    }


    @Override
    public void afterPropertiesSet() throws Exception {

    }

    public int getSubMerchantNumByChannelId(User user) {
        return userDao.findSubMerchantNum(user);
    }

    public int getSubChannelNumByChannelId(User user) {
        return userDao.findSubChannelNum(user);
    }

    public JSONArray findChannelPermission(String userId) {
        JSONArray ids = new JSONArray();

        Menu menu = new Menu();
        menu.setUserId(userId);
        try {
            List<Menu> menus = menuDao.findChannelPermissionByUserId(menu);
            for (Menu m : menus) {
                ids.add(m.getId());
            }
        } catch (Exception ex) {

        }

        return ids;
    }

    public JSONArray findMerchantPermission(String userId) {
        JSONArray ids = new JSONArray();

        Menu menu = new Menu();
        menu.setUserId(userId);
        try {
            List<Menu> menus = menuDao.findMerchantPermissionByUserId(menu);
            for (Menu m : menus) {
                ids.add(m.getId());
            }
        } catch (Exception ex) {

        }

        return ids;
    }

    public JSONArray findPermissionForUser(String userId, String userType) {
        Menu menu = new Menu();
        menu.setUserId(userId);
        List<Menu> menus = null;
        if ("0".equals(userType)) {  // Channel用户
            menus = menuDao.findChannelPermissionByUserId(menu);
        } else {   // Merchant用户
            menus = menuDao.findMerchantPermissionByUserId(menu);
        }
        JSONArray ids = new JSONArray();
        for (Menu m : menus) {
            ids.add(m.getId());
        }
        return ids;
    }

    @Transactional(readOnly = false)
    public boolean modifyUserPermission(String uid, String[] addPermissions, String[] delPermissions) {
        try {
            User user = UserUtils.get(uid);

            if (addPermissions != null) {
                ArrayList<Menu> menus = new ArrayList<Menu>();
                for (String permissionId : addPermissions) {
                    Menu m = new Menu();
                    m.setUserId(uid);
                    m.setId(permissionId);
                    menus.add(m);
                }
                this.addPermissionDistribute(menus);
                UserUtils.clearCache(user);
            }

            if (delPermissions != null) {
                List<User> users = userDao.findAllSubUser(user);
                this.delPermissionDistribute(users, Arrays.asList(delPermissions));
                for (User u : users) {
                    UserUtils.clearCache(u);
                }
            }

            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    protected void addPermissionDistribute(List<Menu> menus) {
        Map map = new HashMap();
        map.put("menus", menus);
        menuDao.addPermissionForUser(map);
    }

    protected void delPermissionDistribute(List<User> users, List<String> menus) {
        Map map = new HashMap();
        map.put("users", users);
        map.put("menus", menus);
        menuDao.delPermissionForUser(map);
    }

    public void addDefaultPermissionDistributeForChannel(String userId) {
        List<Menu> menus = menuDao.findDefaultMenu();
        for (Menu m : menus) {
            m.setUserId(userId);
        }
        addPermissionDistribute(menus);
    }

    @Transactional(readOnly = false)
    public void addWhite(String mac, String uid) {
        Map map = new HashMap();
        map.put("mac", mac);
        map.put("uid", uid);
        map.put("type", 0);
        systemDao.addWhiteAndBlackForUser(map);
    }
}
